<template>
  <div>
    <div class="stream">
      <el-input v-model="text" style="width: 500px" clearable @keyup.enter.native="getStreamData(text)"/>
      <el-button type="primary" @click="getStreamData(text)">发送</el-button>
      <el-card class="redata" v-loading="loading" element-loading-spinner="el-icon-loading"
               :element-loading-text=loadingMessage>
        <div v-html="compiledMarkdown" v-if="compiledMarkdown"></div>
        <div v-else>{{ error ? '' : '我是智能api,请输入你想问的任何问题' }}</div>
        {{ error }}
      </el-card>
    </div>
    <div class="stream">
      <el-input v-model="sse_text" style="width: 500px" clearable @keyup.enter.native="sse(sse_text)"/>
      <el-button type="primary" @click="sse(sse_text)">sse流接口</el-button>
      <el-card class="redata" v-loading="loadingSSE" element-loading-spinner="el-icon-loading"
               :element-loading-text=loadingMessageSSE>
        <div v-html="decodedStringMarkdown" v-if="decodedStringMarkdown"></div>
      </el-card>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import { marked } from 'marked';
import hljs from 'highlight.js/lib/core';


export default {
  name: 'event-stream',
  data() {
    return {
      decodedString: "<code>console.log('Hello, World!');</code>",
      // 流式数据
      streamData: '#### 我是智能api,请输入你想问的任何问题\n' +
        '\n' +
        '\n' +
        '\n' +
        '我能做很多，例如：\n' +
        '\n' +
        '- 智能回答问题\n' +
        '- 智能写文档\n' +
        '- 智能写代码\n' +
        '- and more\n' +
        '\n',
      text: '',
      sse_text: '',
      loading: false,
      loadingSSE: false,
      error: null,
      sse_error: null,
      loadingMessage: '不要着急，正在处理中...',
      loadingMessageSSE: 'sse接口正在请求中',
    };
  },
  computed: {
    compiledMarkdown() {
      return marked(this.streamData, {
        highlight: function (markdown) {
          return hljs.highlightAuto(markdown).value;
        }
      });
    },
    decodedStringMarkdown() {
      return marked(this.decodedString, {
        highlight: function (markdown) {
          return hljs.highlightAuto(markdown).value;
        }
      });
    }
  },
  mounted() {
    // languages.forEach(e => {
    //   hljs.registerLanguage(e, jsHighlight);
    // });
    // hljs.highlightAll();
  },
  methods: {
    sse(text){
      this.loadingSSE = true;
      let eventSource = new EventSource(`/event/sse?text=${text}`);
      eventSource.onmessage = (event) => {
        this.loadingSSE = false;
        const decoder = new TextDecoder('utf-8'); // 创建 TextDecoder 对象
        const data = atob(event.data); // 将 base64 编码字符串转换为二进制数据
        this.decodedString = decoder.decode(new Uint8Array([...data].map(c => c.charCodeAt(0)))); // 将二进制数据转换为字符串
      };
      eventSource.addEventListener('message', event => {

      });
      eventSource.addEventListener('error', event => {
        if (event.readyState === EventSource.CLOSED) {
          console.log('event was closed');
        }
      });
      eventSource.addEventListener('close', event => {
        console.log(event.type);
        eventSource.close();
      });
    },
    getStreamData(text) {
      try {
        this.loading = true;
        // 发送请求
        axios.post('/api/chat-process', { prompt: text, 'options': { 'parentMessageId': '' } })
          .then(response => {
            const lines = response.data.split('\n');
            for (let i = 0; i < lines.length; i++) {
              setTimeout(() => {
                const line = lines[i].trim();
                if (line) {
                  const data = JSON.parse(line);
                  if (typeof data.delta === 'string') this.streamData = data.text;
                  this.loading = false;
                  this.error = null;
                  // this.renderMessages();
                }
              }, i * 10);
            }
          })
          .catch(error => {
            console.error('Error:', error);
          });
        // 取消定时器
      } catch (err) {
        // 处理错误
        this.error = err.message;
        this.loading = false;
      }
    }
  }
};
</script>

<style type="text/scss" lang="scss" scoped>
.stream {
  padding: 20px;
}

.redata {
  margin-top: 20px;
  padding: 20px;
}
</style>

